package tech.hdis.framework.utils.tool;

import java.io.UnsupportedEncodingException;
import java.util.Calendar;

/**
 * byte与int,long,String的类型转化
 *
 * @author 黄志文
 */
public class DataConvert {
    private static final String CHARSET = "UTF-8";
    public static final String GB18030 = "GB18030";
    public static final String ISO8859_1 = "ISO-8859-1";

    /**
     * 获取byte的值，范围是0~255
     *
     * @param b
     * @return
     */
    public static int getByteValue(byte b) {
        return b & 0xff;
    }

    public static byte int2Byte(int intData) {
        return (byte) intData;
    }

    /**
     * <p>
     * short转byte[],数组从左到右，高位到低位
     * </p>
     * 由于java没有unsigned类型，所以用int存short的值
     *
     * @param shortData
     * @return byte[]:byteData
     */
    public static byte[] short2bytes(int shortData) {
        byte[] byteData = new byte[2];
        for (int i = 0; i < 2; i++) {
            int offset = i * 8;
            byteData[i] = (byte) (shortData >> offset);
        }
        reversalBytes(byteData);
        return byteData;
    }

    /**
     * int转byte[],数组从左到右，数组从左到右，高位到低位
     *
     * @param intData
     * @return byte[]:byteData
     */
    public static byte[] int2bytes(int intData) {
        byte[] byteData = new byte[4];
        for (int i = 0; i < 4; i++) {
            int offset = i * 8;
            byteData[i] = (byte) (intData >> offset);
        }
        reversalBytes(byteData);
        return byteData;
    }

    /**
     * long转byte[],数组从左到右，数组从左到右，高位到低位
     *
     * @param longData
     * @return byte[]:byteData
     */
    public static byte[] long2bytes(long longData) {
        byte[] byteData = new byte[8];
        for (int i = 0; i < 8; i++) {
            int offset = i * 8;
            byteData[i] = (byte) (longData >> offset);
        }
        reversalBytes(byteData);
        return byteData;
    }

    /**
     * bytes转short,数组从左到右，依次是高位到低位
     *
     * @param bytes
     * @return short
     */
    public static short bytes2short(byte[] bytes) {
        short shortData = 0;
        int len = bytes.length <= 2 ? bytes.length : 2;
        for (int i = 0; i < len; i++) {
            shortData <<= 8;
            shortData |= (bytes[i] & 0xff);
        }
        return shortData;
    }

    /**
     * bytes转int,数组从左到右，依次是高位到低位
     *
     * @param bytes
     * @return int
     */
    public static int bytes2int(byte[] bytes) {
        int intData = 0;
        int len = bytes.length <= 4 ? bytes.length : 4;
        for (int i = 0; i < len; i++) {
            intData <<= 8;
            intData |= (bytes[i] & 0xff);
        }
        return intData;
    }

    /**
     * bytes中选取少于等4个字节转int
     *
     * @param bytes 包含int字节的数组
     * @param start int字节在数组中起始index
     * @param len   int字节长度 不可大于8
     * @return 如果起始start加上len大于bytes长度将返回-1
     */
    public static int bytes2int(byte[] bytes, int start, int len) {
        int intData = 0;
        int length = len <= 4 ? start + len : start + 4;
        if (length > bytes.length) {
            return -1;
        }
        for (int i = start; i < length; i++) {
            intData <<= 8;
            intData |= (bytes[i] & 0xff);
        }
        return intData;
    }

    /**
     * bytes转long
     *
     * @param bytes 数组从左到右，依次是高位到低位
     * @return long
     */
    public static long bytes2long(byte[] bytes) {
        long longData = 0;
        int len = bytes.length <= 8 ? bytes.length : 8;
        for (int i = 0; i < len; i++) {
            longData <<= 8;
            longData |= (bytes[i] & 0xff);
        }
        return longData;
    }

    /**
     * bytes中选取少于等8个字节转long
     *
     * @param bytes 包含long字节的数组
     * @param start long字节在数组中起始index
     * @param len   long字节长度 不可大于8
     * @return 如果起始start加上len大于bytes长度将返回-1
     */
    public static long bytes2long(byte[] bytes, int start, int len) {
        long longData = 0;
        int length = len <= 8 ? start + len : start + 8;
        if (length > bytes.length) {
            return -1;
        }
        for (int i = start; i < length; i++) {
            longData <<= 8;
            longData |= (bytes[i] & 0xff);
        }
        return longData;
    }

    /**
     * bytes转String
     *
     * @param bytes
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String bytes2string(byte[] bytes) {
        if (bytes == null) {
            return "";
        }
        String newStr = null;
        try {
            newStr = new String(bytes, CHARSET).trim();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return newStr;
    }

    /**
     * bytes转String
     *
     * @param bytes
     * @param charset
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String bytes2string(byte[] bytes, String charset) {
        if (bytes == null) {
            return "";
        }
        String newStr = null;
        try {
            newStr = new String(bytes, charset).trim();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return newStr;
    }

    /**
     * bytes中指定子数组转String
     *
     * @param bytes
     * @param charset
     * @param start
     * @param len
     * @return
     */
    public static String bytes2string(byte[] bytes, String charset, int start, int len) {
        if (bytes == null) {
            return "";
        }
        if (start + len > bytes.length) {
            len = bytes.length - start;
        }
        String newStr = null;
        try {
            byte[] tmp = new byte[len];
            System.arraycopy(bytes, start, tmp, 0, len);
            newStr = new String(tmp, CHARSET).trim();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return newStr;
    }

    /**
     * String转bytes
     *
     * @param str
     * @return
     * @throws UnsupportedEncodingException
     */
    public static byte[] string2bytes(String str) throws UnsupportedEncodingException {
        if (str == null) {
            return null;
        }
        return str.getBytes(CHARSET);
    }

    /**
     * String转bytes
     *
     * @param str
     * @param charset
     * @return
     * @throws UnsupportedEncodingException
     */
    public static byte[] string2bytes(String str, String charset) throws UnsupportedEncodingException {
        if (str == null) {
            return null;
        }
        return str.getBytes(charset);
    }

    /**
     * 将byte转化成16进制的字符串 byte=10,String=0a
     *
     * @param b byte
     * @return String hex
     */
    public static String byte2hex(byte b) {
        int value = b & 0xff;
        String hexVaule = Integer.toHexString(value);
        if (hexVaule.length() < 2) {
            hexVaule = "0" + hexVaule;
        }
        return hexVaule;
    }

    /**
     * 将byte[]转化成16进制的字符串 byte[]=10,11,12,String=0a0b0c
     *
     * @param bytes
     * @return String hex
     */
    public static String bytes2hex(byte[] bytes) {
        String hex = "";
        for (int i = 0; i < bytes.length; i++) {
            int value = bytes[i] & 0xff;
            String hexVaule = Integer.toHexString(value);
            if (hexVaule.length() < 2) {
                hexVaule = "0" + hexVaule;
            }
            hex += hexVaule;
        }
        return hex;
    }

    /**
     * 将byte[] 指定子数组转化成16进制的字符串 byte[]=10,11,12,String=0a0b0c
     *
     * @param bytes
     * @param start 子数组起始位置
     * @param len   子数组长度
     * @return
     */
    public static String bytes2hex(byte[] bytes, int start, int len) {
        String hex = "";
        int length = start + len;
        if (length > bytes.length) {
            return hex;
        }

        for (int i = start; i < length; i++) {
            int value = bytes[i] & 0xff;
            String hexVaule = Integer.toHexString(value);
            if (hexVaule.length() < 2) {
                hexVaule = "0" + hexVaule;
            }
            hex += hexVaule;
        }
        return hex;
    }

    /**
     * byte[]=10,11,12,String=0a0b0c 将16进制的字符串转为byte数组，如果hex的长度不是偶数，则首位补0
     *
     * @param hex
     * @return
     */
    public static byte[] hex2bytes(String hex) {
        if (hex == null || hex.length() < 1) {
            return null;
        }

        // 如果长度不是偶数，则前面补0
        if (hex.length() % 2 != 0) {
            hex = "0" + hex;
        }

        byte[] bytes = new byte[(hex.length() + 1) / 2];

        try {
            for (int i = 0, j = 0; i < hex.length(); i += 2) {
                byte hight = (byte) (Character.digit(hex.charAt(i), 16) & 0xff);
                byte low = (byte) (Character.digit(hex.charAt(i + 1), 16) & 0xff);
                bytes[j++] = (byte) (hight << 4 | low);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        return bytes;
    }

    /**
     * byte[]转为坐标类型,先转为int，再除以10^6
     * <p>
     * 这里的坐标数据只支持4byte，坐标有正负数
     * </p>
     *
     * @param bytes bytes
     * @return double
     */
    public static double bytes2Coordinate(byte[] bytes) {
        double d = 0;
        long l = bytes2int(bytes);
        d = l / 1000000.0;
        return d;
    }

    /**
     * 将坐标类型转为byte数组
     * <ul>
     * <li>普通精度：将坐标值乘以10^6<li>
     * <li>高精度：将坐标值乘以10^12<li>
     * </ul>
     *
     * @param coordinate  需要转为byte数组的坐标值
     * @param isPrecision 是否高精度，如果true，返回8byte，如果否，返回4byte
     * @return
     */
    public static byte[] coordinate2Bytes(double coordinate, boolean isPrecision) {
        if (isPrecision) {
            long val = (long) (coordinate * 1000000000000L);
            return long2bytes(val);
        } else {
            int val = (int) (coordinate * 1000000);
            return int2bytes(val);
        }
    }

    /**
     * <p>
     * 将src的内容复制到dest中
     * </p>
     * <ul>
     * <li>如果src为null，则dest也为null</li>
     * <li>如果dest为null或者dest.length&lt;src.length，则dest=new byte[src.length]</li>
     * </ul>
     *
     * @param src  要复制的byte[]
     * @param dest 复制的目标byte[]
     */
    public static void copyBytes(byte[] src, byte[] dest) {
        if (src == null) {
            dest = null;
        }
        if (dest == null || dest.length < src.length) {
            dest = new byte[src.length];
        }
        System.arraycopy(src, 0, dest, 0, src.length);
    }

    /**
     * <p>
     * 将appendBytes追加到oldBytes后面
     * <ul>
     * <li>1.如果appendBytes为null，则直接返回oldBytes</li>
     * <li>2.如果oldBytes为null，则直接返回appendBytes</li>
     * </ul>
     * </p>
     *
     * @param oldBytes    原数据
     * @param appendBytes 需要追加的数据
     * @return
     */
    public static byte[] appendBytes(byte[] oldBytes, byte[] appendBytes) {
        if (appendBytes == null) {
            return oldBytes;
        }

        if (oldBytes == null) {
            return appendBytes;
        }

        int len = 0;
        // 计算合并后的长度
        len = oldBytes.length + appendBytes.length;
        // 申请合并后的内存空间
        byte[] bytes = new byte[len];
        System.arraycopy(oldBytes, 0, bytes, 0, oldBytes.length);
        System.arraycopy(appendBytes, 0, bytes, oldBytes.length, appendBytes.length);
        return bytes;
    }

    /**
     * 获得short类型数据的无符号值
     *
     * @param data
     * @return
     */
    public static int getUnsignedShort(short data) {
        return data & 0xffff;
    }

    /**
     * 获得int类型的unsigned值
     */
    public static long getUnsignedInt(int data) {
        return data & 0xffffffffL;
    }

    /**
     * 翻转byte数组
     *
     * @param bytes
     */
    public static void reversalBytes(byte[] bytes) {
        byte b = 0;
        int length = bytes.length;
        int half = length / 2;
        for (int i = 0; i < half; i++) {
            b = bytes[i];
            bytes[i] = bytes[length - 1 - i];
            bytes[length - 1 - i] = b;
        }
    }

    /**
     * 截取数据
     *
     * @param data  要截取的源数据
     * @param start 开始截取位置(包含该点数据)
     * @param end   截取结束位置(包含该点数据)
     * @return
     */
    public static byte[] getSubData(byte[] data, int start, int end) {
        int length = end - start + 1;
        return getDataSequence(data, start, length);
    }

    /**
     * 获取子串
     *
     * @param data  要获取子串的原始数据
     * @param start 开始位置，包含改节点
     * @param len   要截取的子串长度
     * @return
     */
    public static byte[] getDataSequence(byte[] data, int start, int len) {
        byte[] returnData = new byte[len];
        System.arraycopy(data, start, returnData, 0, len);
        return returnData;
    }

    /**
     * 将传入的bytes数组转为Calendar
     * <ul>
     * <li>1.data为空或者长度为0，返回当前时间</li>
     * <li>2.data长度超过8byte，截取前面8byte</li>
     * <li>3.data长度小于等于4，怎默认是获取从1970年1月1日 00:00:00到现在的累积秒数</li>
     * <li>3.data长度大于4且小于等于8，怎默认是获取从1970年1月1日 00:00:00到现在的累积毫秒数</li>
     * </ul>
     *
     * @param data
     * @return
     */
    public static Calendar bytes2Calendar(byte[] data) {
        Calendar calendar = Calendar.getInstance();
        if (data != null && data.length > 0) {
            long millis = 0;
            // 超过long，截取8byte
            if (data.length > 8) {
                data = getDataSequence(data, 0, 8);
            }
            if (data.length <= 4) {
                //精确到s
                millis = bytes2long(data) * 1000;
            } else if (data.length <= 8) {
                //本身是精确到ms
                millis = bytes2long(data);
            }
            calendar.setTimeInMillis(millis);
        }
        return calendar;
    }

    /**
     * 将Calendar转为时间戳
     *
     * @param time      要转为时间戳的时间
     * @param isSeconds 是否以秒为单位，如果是，则返回4个byte，如果不是则表示以毫秒为单位，返回8个字节
     * @return 返回4个字节数组或者8个字节数组
     */
    public static byte[] calendar2Bytes(Calendar time, boolean isSeconds) {
        byte[] data = new byte[0];
        if (time == null) {
            return data;
        }
        long millis = time.getTimeInMillis();
        if (isSeconds) {
            data = int2bytes((int) (millis / 1000));
        } else {
            data = long2bytes(millis);
        }
        return data;
    }

    /**
     * 16进制字符串转10进制字符串
     *
     * @param hexStr
     * @return
     */
    public static String hexStr2DecStr(String hexStr) {
        String strDecData = null;
        Long lngNum = Long.parseLong(hexStr, 16);
        strDecData = String.valueOf(lngNum);
        return strDecData;
    }

    /**
     * 十进制字符串转16进制字符串
     *
     * @param strDecData
     * @param intBytes
     * @return
     */
    public static String decStr2HexStr(String strDecData, int intBytes) {
        String strRet = null;
        long intNum = Long.parseLong(strDecData, 10);
        String strHexData = decInt2HexStr(intNum);
        String strTempRet = String.valueOf(strHexData);
        int intLen = strTempRet.length();
        int intTempBytes = intBytes * 2 - intLen;
        String strTempByte = null;

        for (int i = 0; i < intTempBytes; ++i) {
            if (strTempByte == null) {
                strTempByte = "0";
            } else {
                strTempByte = strTempByte + "0";
            }
        }

        if (strTempByte == null) {
            strRet = strTempRet;
        } else {
            strRet = strTempByte + strTempRet;
        }

        return strRet;
    }

    /**
     * 十进制数据转16进行字符串
     *
     * @param intDecData
     * @return
     */
    public static String decInt2HexStr(long intDecData) {
        String str = "";
        long sun = intDecData / 16L;
        int yuShu = (int) (intDecData % 16L);

        for (str = number2Letter(yuShu); sun > 0L; str = number2Letter(yuShu) + str) {
            yuShu = (int) (sun % 16L);
            sun /= 16L;
        }

        return str;
    }


    /**
     * 数字转字母
     *
     * @param intData
     * @return
     */
    private static String number2Letter(int intData) {
        String strRet = "";
        switch (intData) {
            case 10:
                strRet = "A";
                break;
            case 11:
                strRet = "B";
                break;
            case 12:
                strRet = "C";
                break;
            case 13:
                strRet = "D";
                break;
            case 14:
                strRet = "E";
                break;
            case 15:
                strRet = "F";
                break;
            default:
                strRet = "" + intData;
        }

        return strRet;
    }

}
